/*
 * task_loader.cpp
 *
 *  Created on: 2023年10月18日
 *      Author: Dylan.Gao
 */

#include <dm/export.hpp>

#define DM_API_OS_SYS DM_API_EXPORT

#include <dm/os/sys/task_loader.hpp>
#include <dm/env/cfg.hpp>
#include <dm/string/stringlist.hpp>
#include <dm/os/log/logger.hpp>

namespace dm{
namespace os{
namespace sys{

static const char* logModule = "CTaskLoader.sys.os.dm";

CTaskLoader::CTaskLoader():m_db(),m_resultSet(){
	log().debug(THISMODULE "创建对象");
}

CTaskLoader::~CTaskLoader(){
	m_resultSet = NULL;
	m_db = NULL;
	log().debug(THISMODULE "销毁对象");
}

bool CTaskLoader::createTable(){
	if( !m_db ){
		dm::env::CCfg& cfg = dm::env::CCfg::ins();
		m_db = dm::os::createDb(cfg.sys_dbName().c_str(),cfg.sys_dbHost().c_str(), cfg.sys_dbEngine().c_str(), cfg.sys_dbPort());
		if( !m_db->connect(cfg.sys_dbUsr().c_str(), cfg.sys_dbPwd().c_str()) )
			return false;
	}

	switch( m_db->dbType() ){
	case dm::os::CDb::DtSqlite:
		return m_db->exec("CREATE TABLE t_task (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, descr varchar(255) NOT NULL, program varchar(255) NOT NULL, cmdline varchar(255), type varchar(255) NOT NULL, start_mode varchar(255) NOT NULL, start_datetime varchar(255), host_a_id integer(10), host_b_id integer(10), group_id integer(10), delay_secs integer(10), alive_secs integer(10))");
	case dm::os::CDb::DtPg:
		return m_db->exec("CREATE TABLE t_task (id SERIAL NOT NULL, descr varchar(255) NOT NULL, program varchar(255) NOT NULL, cmdline varchar(255), type varchar(255) NOT NULL, start_mode varchar(255) NOT NULL, start_datetime varchar(255), host_a_id int4, host_b_id int4, group_id int4, delay_secs int4, alive_secs int4, PRIMARY KEY (id))");
	case dm::os::CDb::DtMysql:
		return m_db->exec("CREATE TABLE t_task (id int(10) NOT NULL AUTO_INCREMENT, descr varchar(255) NOT NULL, program varchar(255) NOT NULL, cmdline varchar(255), type varchar(255) NOT NULL, start_mode varchar(255) NOT NULL, start_datetime varchar(255), host_a_id int(10), host_b_id int(10), group_id int(10), delay_secs int(10), alive_secs int(10), PRIMARY KEY (id))");
	default:
		return false;
	}
}

bool CTaskLoader::addTask( id_t& id,const char* descr,const char* program,const char* cmdline,STaskInfo::EType type,STaskInfo::EStartMode startMode,id_t hostA,id_t hostB,id_t group,CTimeStamp::s_t delay,CTimeStamp::s_t alive ){
	if( !m_db ){
		dm::env::CCfg& cfg = dm::env::CCfg::ins();
		m_db = dm::os::createDb(cfg.sys_dbName().c_str(),cfg.sys_dbHost().c_str(), cfg.sys_dbEngine().c_str(), cfg.sys_dbPort());
		if( !m_db->connect(cfg.sys_dbUsr().c_str(), cfg.sys_dbPwd().c_str()) )
			return false;
	}

	char sql[256];
	std::sprintf(sql,"INSERT INTO t_task(descr,program,cmdline,type,start_mode,start_datetime,host_a_id,host_b_id,group_id,delay_secs,alive_secs) values ('%s','%s','%s','%s','%s','%s',%d,%d,%d,%d,%d)",
			descr,program,cmdline,type2string(type),startMode2string(startMode),hostA,hostB,group,delay,alive);
	id = m_db->execWithLastId(sql);

	return id>=0;
}

bool CTaskLoader::delTask( const id_t& id ){
	if( !m_db ){
		dm::env::CCfg& cfg = dm::env::CCfg::ins();
		m_db = dm::os::createDb(cfg.sys_dbName().c_str(),cfg.sys_dbHost().c_str(), cfg.sys_dbEngine().c_str(), cfg.sys_dbPort());
		if( !m_db->connect(cfg.sys_dbUsr().c_str(), cfg.sys_dbPwd().c_str()) )
			return false;
	}

	char sql[512];
	std::sprintf(sql,"DELETE FROM t_task WHERE id=%d",id);
	return m_db->exec(sql);
}

bool CTaskLoader::delTask( const char* program ){
	if( !m_db ){
		dm::env::CCfg& cfg = dm::env::CCfg::ins();
		m_db = dm::os::createDb(cfg.sys_dbName().c_str(),cfg.sys_dbHost().c_str(), cfg.sys_dbEngine().c_str(), cfg.sys_dbPort());
		if( !m_db->connect(cfg.sys_dbUsr().c_str(), cfg.sys_dbPwd().c_str()) )
			return false;
	}

	char sql[512];
	std::sprintf(sql,"DELETE FROM t_task WHERE program='%s'",program);
	return m_db->exec(sql);
}

bool CTaskLoader::addALoaded( record_t& r ){
	id_t id;
	record_t::CIdReader idReader;
	if( !r.get(&id, idReader) ){
		log().warnning(THISMODULE "读取ID失败");
		return false;
	}

	m_loadedRecordsId.push_back(id);

	return true;
}

bool CTaskLoader::filterLoaded(){
	if( !m_db ){
		dm::env::CCfg& cfg = dm::env::CCfg::ins();
		m_db = dm::os::createDb(cfg.sys_dbName().c_str(),cfg.sys_dbHost().c_str(), cfg.sys_dbEngine().c_str(), cfg.sys_dbPort());
		if( !m_db->connect(cfg.sys_dbUsr().c_str(), cfg.sys_dbPwd().c_str()) ){
			log().warnning(THISMODULE "连接数据库失败");
			return false;
		}
	}

	if( m_loadedRecordsId.size()==0 ){
		m_resultSet = m_db->query("select id,descr,program,cmdline,type,start_mode,start_datetime,host_a_id,host_b_id,group_id,delay_secs,alive_secs from t_task order by id");
		if( !m_resultSet ){
			log().warnning(THISMODULE "查询记录失败");
			return false;
		}

		return true;
	}

	dm::string::CStringList sql;
	char ids[64];
	sql.append("select id,descr,program,cmdline,type,start_mode,start_datetime,host_a_id,host_b_id,group_id,delay_secs,alive_secs from t_task where id not in (");
	for( int i=0;i<m_loadedRecordsId.size();++i ){
		if( i==0 )
			std::sprintf(ids,"%ld",m_loadedRecordsId[i]);
		else
			std::sprintf(ids,",%ld",m_loadedRecordsId[i]);

		sql.append(ids);
	}
	sql.append(") order by id");

	m_resultSet = m_db->query(sql.toString().c_str());
	if( !m_resultSet ){
		log().warnning(THISMODULE "查询结果失败");
		return false;
	}

	return true;
}

/**
 * 移动记录
 * @return
 */
bool CTaskLoader::next(){
	if( m_resultSet )
		return m_resultSet->next();

	log().debug(THISMODULE "记录未初始化");
	return false;
}

/**
 * 加载记录
 * @param record
 * @return
 */
bool CTaskLoader::loadRecord( record_t& record ){
	if( !m_resultSet ){
		log().info(THISMODULE "结果集不存在");
		return false;
	}

	int p = 0;
	STaskInfo taskInfo;

	taskInfo.id = m_resultSet->asInt64(p++);
	taskInfo.desc = m_resultSet->asString(p++).c_str();
	taskInfo.program = m_resultSet->asString(p++).c_str();
	taskInfo.cmdline = m_resultSet->asString(p++,"").c_str();
	taskInfo.type = string2type(m_resultSet->asString(p++,"").c_str());
	taskInfo.startMode = string2startMode(m_resultSet->asString(p++,"").c_str());
	taskInfo.dateTime.fromString(m_resultSet->asString(p++,"").c_str());
	taskInfo.mainHost = m_resultSet->asInt(p++,-1);
	taskInfo.backHost = m_resultSet->asInt(p++,-1);
	taskInfo.hostGroup = m_resultSet->asInt(p++,-1);
	taskInfo.delaySeconds = m_resultSet->asInt(p++,0);
	taskInfo.aliveSeconds = m_resultSet->asInt(p++,0);

	STaskState taskState;

	taskState.state = STaskState::Uninit;
	taskState.pid = -1;
	taskState.tsBegin  = dm::CTimeStamp();
	taskState.tsStop = dm::CTimeStamp();
	taskState.tsExec = dm::CTimeStamp();
	taskState.tsCheck = dm::CTimeStamp();

	taskState.rtsRefresh = dm::CRunTimeStamp();

	record_t::CNormalLoader loader(&taskInfo,&taskState);

	return record.reload(loader, m_ts, m_rts);
}

bool CTaskLoader::reloadRecord( record_t& record ){
	if( !m_db ){
		dm::env::CCfg& cfg = dm::env::CCfg::ins();
		m_db = dm::os::createDb(cfg.sys_dbName().c_str(),cfg.sys_dbHost().c_str(), cfg.sys_dbEngine().c_str(), cfg.sys_dbPort());
		if( !m_db->connect(cfg.sys_dbUsr().c_str(), cfg.sys_dbPwd().c_str()) ){
			log().warnning(THISMODULE "连接数据库失败");
			return false;
		}
	}

	char sql[128];
	std::sprintf(sql,"select id,descr,program,cmdline,type,start_mode,start_datetime,host_a_id,host_b_id,group_id,delay_secs,alive_secs from t_task where id=%d",record.info.id);

	m_resultSet = m_db->query(sql);
	if( !m_resultSet || !m_resultSet->next() ){
		log().warnning(THISMODULE "查询记录(id:%d)失败",record.info.id);
		return false;
	}

	return loadRecord(record);
}

static const char* TypeStrings[STaskInfo::TypeMax] = {
		"Normal","Device","Forward","Caculate","Ui","System"
};

const char* CTaskLoader::type2string( STaskInfo::EType type ){
	if( type<0 || type>=STaskInfo::TypeMax )
		return nullptr;

	return TypeStrings[type];
}

STaskInfo::EType CTaskLoader::string2type( const char* str ){
	for( int i=0;i<STaskInfo::TypeMax;++i ){
		if( strcmp(str,TypeStrings[i])==0 )
			return STaskInfo::EType(i);
	}

	return STaskInfo::TypeMax;
}

static const char* StartModeStrings[STaskInfo::StartSundays+1] = {
		"Deny","Daemon","Single","Manual","Secondly","Minutely","Hourly","Daily","Monthly","Yearly",
		"Mondays","Tuesdays","Wednesdays","Thursdays","Fridays","Saturdays","Sundays"
};


const char* CTaskLoader::startMode2string( STaskInfo::EStartMode startMode ){
	if( startMode<0 || startMode>STaskInfo::StartSundays )
		return nullptr;

	return StartModeStrings[startMode];
}

STaskInfo::EStartMode CTaskLoader::string2startMode( const char* str ){
	for( int i=0;i<=STaskInfo::StartSundays;++i ){
		if( strcmp(str,StartModeStrings[i])==0 )
			return STaskInfo::EStartMode(i);
	}

	return STaskInfo::StartDeny;
}

}
}
}


